package com.leo.util.http.builder;

import com.leo.util.http.common.HttpClientConstans;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLInitializationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;
import java.io.*;
import java.net.UnknownHostException;

/**
 * @author liusl
 * @version 1.0
 * @date 2019/7/17 14:27
 */
public class HttpClientBuilder {
    private static Logger logger = LoggerFactory.getLogger(HttpClientBuilder.class);
    private static CloseableHttpClient httpClient;
    private static CloseableHttpClient httpsClient;
    /**
     * 连接池
     */
    private static PoolingHttpClientConnectionManager connHttpManager;
    private static PoolingHttpClientConnectionManager connHttpsManager;

    private HttpClientBuilder() {
    }

    public static synchronized  CloseableHttpClient getInstance(String url) {
        if(url.startsWith(HttpClientConstans.HTTPS)){
            if(httpsClient==null){
                SSLContext sslContext = SSLBuilder.getInstance();
                Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                            .register("http", PlainConnectionSocketFactory.INSTANCE)
                            .register("https", new SSLConnectionSocketFactory(sslContext))
                            .build();
                connHttpsManager = new PoolingHttpClientConnectionManager(registry);
                // 连接池最大连接数
                connHttpsManager.setMaxTotal(1000);
                // 每个路由最大连接数
                connHttpsManager.setDefaultMaxPerRoute(20);
                httpsClient = getHttpClient();
            }
            return httpsClient;
        }else {
            if (httpClient == null) {
                try {
                    // 注册
                    Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                            .register("http", PlainConnectionSocketFactory.INSTANCE)
                            .build();
                    // ssl注册到连接池
                    connHttpManager = new PoolingHttpClientConnectionManager(registry);
                    // 连接池最大连接数
                    connHttpManager.setMaxTotal(1000);
                    // 每个路由最大连接数
                    connHttpManager.setDefaultMaxPerRoute(20);
                    httpClient = getHttpClient();
                } catch (SSLInitializationException e) {
                    e.printStackTrace();
                }
            }
             return httpClient;
        }

    }

    /**
     * 获取客户端连接对象
     *
     * @return CloseableHttpClient
     */
    private static  CloseableHttpClient getHttpClient() {

        // 配置请求参数
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(5000).
                        setConnectTimeout(5000).
                        setSocketTimeout(5000).
                        build();
        // 配置超时回调机制
        HttpRequestRetryHandler retryHandler = (exception, executionCount, context) -> {
            // 如果已经重试了3次，就放弃
            if (executionCount >= HttpClientConstans.MAXIMUM_RETRIES_NUMBER) {
                return false;
            }
            // 如果服务器丢掉了连接，那么就重试
            if (exception instanceof NoHttpResponseException) {
                return true;
            }
            // 不要重试SSL握手异常
            if (exception instanceof SSLHandshakeException) {
                return false;
            }
            // 超时
            if (exception instanceof InterruptedIOException) {
                return true;
            }
            // 目标服务器不可达
            if (exception instanceof UnknownHostException) {
                return false;
            }
            // 连接被拒绝
            // ssl握手异常
            if (exception instanceof SSLException) {
                return false;
            }
            HttpClientContext clientContext = HttpClientContext.adapt(context);
            HttpRequest request = clientContext.getRequest();
            // 如果请求是幂等的，就再次尝试
            return !(request instanceof HttpEntityEnclosingRequest);
        };

        return HttpClients.custom()
                .setConnectionManager(connHttpManager)
                .setDefaultRequestConfig(requestConfig)
                .setRetryHandler(retryHandler)
                .build();

    }
}
